using System;
using System.Collections.Generic;
using System.Reflection;
using CodePlex.DependencyInjection;
using CodePlex.TfsLibrary;
using CodePlex.TfsLibrary.ClientEngine;

namespace CodePlex.CodePlexClientLibrary
{
    public class CommandLineHelper
    {
        readonly List<DependencyContainer> commandContainers = new List<DependencyContainer>();
        readonly Dictionary<ICommandInfo, ICommand> commands;
        readonly DependencyContainer container;

        public CommandLineHelper(DependencyContainer container)
        {
            this.container = container;
            commands = new Dictionary<ICommandInfo, ICommand>();
        }

        public ICommandInfo FindByCommand(ICommand command)
        {
            foreach (KeyValuePair<ICommandInfo, ICommand> pair in GetCommands())
                if (pair.Value.GetType() == command.GetType())
                    return pair.Key;

            return null;
        }

        public Pair<ICommandInfo, ICommand> FindByCommandName(string cmdName)
        {
            foreach (KeyValuePair<ICommandInfo, ICommand> kvp in GetCommands())
                if ((string.Compare(kvp.Key.CommandName, cmdName, true) == 0) || (string.Compare(kvp.Key.AltName, cmdName, true) == 0))
                    return new Pair<ICommandInfo, ICommand>(kvp);

            return null;
        }

        public Dictionary<OptionAttribute, PropertyInfo> GetCommandOptions(ICommand cmd)
        {
            Dictionary<OptionAttribute, PropertyInfo> result = new Dictionary<OptionAttribute, PropertyInfo>();

            foreach (PropertyInfo propInfo in cmd.GetType().GetProperties())
            {
                foreach (OptionAttribute attr in propInfo.GetCustomAttributes(typeof(OptionAttribute), true))
                {
                    if (!propInfo.CanWrite)
                        throw new InvalidOperationException("[Option] on " + cmd.GetType().FullName + "." + propInfo.Name + " is invalid without a setter");

                    result.Add(attr, propInfo);
                }
            }

            return result;
        }

        public Dictionary<ICommandInfo, ICommand> GetCommands()
        {
            return commands;
        }

        public void RegisterCommand<TCommand>()
            where TCommand : ICommand
        {
            container.CacheInstancesOf<TCommand>();
            DependencyContainer newContainer = new DependencyContainer(container);
            newContainer.CacheInstancesOf<ITfsEngine>();
            commandContainers.Add(newContainer);
            RegisterCommand(newContainer.Get<TCommand>());
        }

        public void RegisterCommand(ICommand command)
        {
            foreach (CommandAttribute attrib in command.GetType().GetCustomAttributes(typeof(CommandAttribute), true))
                commands.Add(attrib, command);
        }
    }
}